/*
 * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "led_strip.h"
#include "esp_log.h"
#include "ws2812.h"
#include "lamp_ctrl.h"
#include "main.h"
#include "nvs_value.h"
#include "h03_config.h"

static const char *TAG = "[TOP]";

static led_strip_handle_t led_strip;
notify_color_t led_notify;
uint8_t nlight_colortemp;
uint8_t nlight_brightness;
uint32_t led_color;
uint8_t top_led_mode = 0;

static uint32_t led_color_ex;
static uint8_t led_red_ex;
static uint8_t led_green_ex;
static uint8_t led_blue_ex;

uint16_t blink_delay = 800;

uint32_t colors[9] = {
    0xFF0000, // 0:Red
    0xFF7000, // 1:Orange
    0xFFD800, // 2:Yellow
    0x00FF00, // 3:Green
    0x00FF8F, // 4:cyan1
    0x00FFFF, // 5:cyan2
    0x0000FF, // 6:Blue
    0x8F00FF, // 7:pupple
    0xFF008F, // 8:pupple
};

uint32_t signal_colors[5] = {
    0xF00000, // 0:error
    0x0000F0, // 1:success
    0xF0F000, // 2:waiting
    0xF00000, // 3:network
    0x00F000, // 4:communicate
};

void topLED_set_color(uint32_t color)
{
    event_flag.led_break = 0;

    led_red_ex = (uint8_t)((color >> 16) & 0xFF);
    led_green_ex = (uint8_t)((color >> 8) & 0xFF);
    led_blue_ex = (uint8_t)(color & 0xFF);

    led_strip_set_pixel(led_strip, 0, led_red_ex, led_green_ex, led_blue_ex);
    led_strip_refresh(led_strip);
}

void topLED_toggle(uint32_t LED)
{
    static uint8_t led_toggle_cnt;

    led_toggle_cnt++;
    if(led_toggle_cnt%2 == 0){
        topLED_set_color(LED);
    }else{
        topLED_set_color(0);
    }
}

void msg_receive_led(uint32_t LED)
{
    topLED_set_color(0);
    for(uint8_t i = 0; i < 5; i++)
    {
        topLED_toggle(LED);
        vTaskDelay(70 / portTICK_PERIOD_MS);
    }
}

void topLED_set_blink(uint32_t LED)
{
    event_flag.led_break = 0;
    while(1){
        topLED_set_color(LED);
        for(uint8_t i = 0; i < 4; i++){
            vTaskDelay(100 / portTICK_PERIOD_MS);
            if(event_flag.led_break == 1){
                goto end;
            }
        }
        led_strip_clear(led_strip);
        for(uint8_t i = 0; i < 4; i++){
            vTaskDelay(100 / portTICK_PERIOD_MS);
            if(event_flag.led_break == 1){
                goto end;
            } 
        }
    }
    end:
    event_flag.led_break = 0;
    ESP_LOGI(TAG, "stop blinking");
}      

void topLED_set_breath(uint32_t color, uint16_t delay_ms, uint8_t times)
{
    uint8_t r2;   
    uint8_t g2;  
    uint8_t b2;

    r2 = (uint8_t)((color >> 16) & 0xFF);
    g2 = (uint8_t)((color >> 8) & 0xFF);
    b2 = (uint8_t)(color & 0xFF);

    uint8_t r = 0;
    uint8_t g = 0;
    uint8_t b = 0;
    uint16_t delay_ms_p;
    uint8_t max_step;

    if(delay_ms >= 500){
        max_step = 50;
    }else if(delay_ms >= 200){
        max_step = 20;
    }else{
        max_step = 5;
    }
    delay_ms_p = delay_ms/max_step;

    event_flag.led_break = 0;
    led_strip_clear(led_strip);
    while(1){
        for (uint8_t i = 1; i <= max_step; i++) {
            if(i == 50 && color == 0){
                r2 = 0;
                g2 = 0;
                b2 = 0;
            }
            r = 0 + (r2 - 0) * i / max_step;
            g = 0 + (g2 - 0) * i / max_step;
            b = 0 + (b2 - 0) * i / max_step;
            led_strip_set_pixel(led_strip, 0, r, g, b);
            led_strip_refresh(led_strip);
            vTaskDelay(delay_ms_p / portTICK_PERIOD_MS);
            if(event_flag.led_break == 1){
                goto end;
            } 
        }
        for (uint8_t i = max_step; i > 0; i--) {
            if(i == 50 && color == 0){
                r2 = 0;
                g2 = 0;
                b2 = 0;
            }
            r = 0 + (r2 - 0) * i / max_step;
            g = 0 + (g2 - 0) * i / max_step;
            b = 0 + (b2 - 0) * i / max_step;
            led_strip_set_pixel(led_strip, 0, r, g, b);
            led_strip_refresh(led_strip);
            vTaskDelay(delay_ms_p / portTICK_PERIOD_MS);
            if(event_flag.led_break == 1){
                goto end;
            } 
        }
        if(times != 0){
            times--;
            if(times == 0){
                goto end;
            }
        }
    }
    end:
        event_flag.led_break = 0;
        led_red_ex = r;
        led_green_ex = g;
        led_blue_ex = b;
}      

// static void fade_led(void)
// {
//     uint8_t r,g,b;
//     for(uint8_t i=0;i<50;i++){
//         r = 255*i/50;
//         g = 150*i/50;
//         b = 30*i/50;

//         led_strip_set_pixel(led_strip, 0, r, g, b);
//         led_strip_refresh(led_strip);
//         vTaskDelay(20 / portTICK_PERIOD_MS);
//     }
//     for(uint8_t i=50;i>0;i--){
//         r = 255*i/50;
//         g = 150*i/50;
//         b = 30*i/50;
//         led_strip_set_pixel(led_strip, 0, r, g, b);
//         led_strip_refresh(led_strip);
//         vTaskDelay(20 / portTICK_PERIOD_MS);
//     }
//     led_strip_clear(led_strip);
// }

void topLED_set_fade(uint32_t color, uint16_t delay_ms)
{
    uint8_t r2;   
    uint8_t g2;  
    uint8_t b2;

    r2 = (uint8_t)((color >> 16) & 0xFF);
    g2 = (uint8_t)((color >> 8) & 0xFF);
    b2 = (uint8_t)(color & 0xFF);

    uint8_t r = 0;
    uint8_t g = 0;
    uint8_t b = 0;

    event_flag.led_break = 0;

    for (uint8_t i = 1; i <= 50; i++) {
        if(i == 50 && color == 0){
            r2 = 0;
            g2 = 0;
            b2 = 0;
        }
        r = led_red_ex + (r2 - led_red_ex) * i / 50;
        g = led_green_ex + (g2 - led_green_ex) * i / 50;
        b = led_blue_ex + (b2 - led_blue_ex) * i / 50;
        led_strip_set_pixel(led_strip, 0, r, g, b);
        led_strip_refresh(led_strip);
        vTaskDelay(delay_ms/ 50 / portTICK_PERIOD_MS);
        if(event_flag.led_break == 1){
            break;
        }
    }
    led_red_ex = r;
    led_green_ex = g;
    led_blue_ex = b;
}

void topLED_manage_task(void * parm)
{
    static bool led_blink_flag;
    led_notify = 0;
    event_flag.led_break = 0;
    static uint8_t c;

    for(;;) {
        if(device_attr.demo_mode != 3){
            if(led_notify > 0){
                if(led_notify == 1){
                    ESP_LOGI(TAG, "BLUE_NOTIFICATION");
                    msg_receive_led(signal_colors[1]);
                }else if(led_notify == 2){
                    ESP_LOGI(TAG, "RED_NOTIFICATION");
                    msg_receive_led(signal_colors[0]);
                }else if(led_notify == 3){
                    ESP_LOGI(TAG, "FADE_NOTIFICATION");
                    topLED_set_breath(led_color, blink_delay, 1);
                }
                led_notify = 0;
            }
            if(top_led_mode == 1){
                switch(system_state.main){
                    case BOOTING:
                        ESP_LOGI(TAG, "YELLOW_ON");
                        led_color = signal_colors[2];
                        led_blink_flag = 0;
                        break;
                    case FAST_SCAN:
                        ESP_LOGI(TAG, "YELLOW_ON");
                        led_color = signal_colors[2];
                        led_blink_flag = 0;
                        break;
                    case SELF_TEST:
                        ESP_LOGI(TAG, "GREEN_BLINK");
                        led_color = signal_colors[4];
                        led_blink_flag = 1;
                        break;
                    case SMARTCONFIG:
                        ESP_LOGI(TAG, "RED_BLINK");
                        led_color = signal_colors[3];
                        led_blink_flag = 1;
                        break;
                    case STATION:
                        ESP_LOGI(TAG, "RED_ON");
                        led_color = signal_colors[3];
                        led_blink_flag = 0;
                        break;
                    case MQTT_DISCONNECTED:
                        ESP_LOGI(TAG, "RED_ON");
                        led_color = signal_colors[3];
                        led_blink_flag = 0;
                        break;
                    case NORMAL:
                        ESP_LOGI(TAG, "OFF");
                        led_color = 0x000000;
                        led_blink_flag = 0;
                        break;
                    case OTA:
                        ESP_LOGI(TAG, "GREEN_ON");
                        led_color = signal_colors[4];
                        led_blink_flag = 0;
                        break;
                    default:
                        break;
                }
                led_color_ex = led_color;
                if(led_blink_flag == 0){
                    topLED_set_fade(led_color, 500);
                    while(event_flag.led_break == 0){
                        vTaskDelay(15 / portTICK_PERIOD_MS);
                    }
                }else{
                    topLED_set_blink(led_color);
                }
            }else if(top_led_mode == 2){
                if(present_state == 0){
                    ESP_LOGI(TAG, "TOP_LED OFF");
                    led_color = 0;
                    led_blink_flag = 0;
                }else if(present_state == 1){
                    ESP_LOGI(TAG, "YELLOW_ON");
                    led_color = colors[2];
                    led_blink_flag = 0;
                }else if(present_state == 2){
                    if(timer_count.gesture_detect > 0){
                        ESP_LOGI(TAG, "ORANGE_BLINK");
                        led_color = colors[1];
                        led_blink_flag = 1;
                        if(timer_count.gesture_detect>10){
                            blink_delay = 1600;
                        }else{
                            blink_delay = 800;
                        }
                    }else{
                        ESP_LOGI(TAG, "TOP_LED OFF");
                        led_color = 0;
                        led_blink_flag = 0;
                    }
                }else if(present_state == 3){
                    ESP_LOGI(TAG, "BLUE_ON");
                    led_color = colors[6];
                    led_blink_flag = 0;
                }
                led_color_ex = led_color;
                if(led_blink_flag == 0){
                    topLED_set_fade(led_color, 500);
                    while(event_flag.led_break == 0){
                        vTaskDelay(15 / portTICK_PERIOD_MS);
                    }
                }else{
                    topLED_set_breath(led_color, blink_delay, 0);
                }
            }else if(top_led_mode == 0){
                led_color = 0;
                led_color_ex = led_color;
                led_blink_flag = 0;
                topLED_set_fade(led_color, 500);
                ESP_LOGI(TAG, "led_color:%ld\n",led_color);
                event_flag.led_break = 0;
                while(event_flag.led_break == 0){
                    vTaskDelay(15 / portTICK_PERIOD_MS);
                }
            }
        }else{
            topLED_set_fade(colors[c], 500);
            vTaskDelay(500 / portTICK_PERIOD_MS);
            if(lamp.onoff_status == 1){
                c++;
                if(c > 8){
                    c = 0;
                }
            }
        }
    }
    vTaskDelete(NULL);
}

void led_strip_init(void)
{
    if(device_attr.debug_mode == 0 && system_state.main != FAST_SCAN){
        ESP_LOGI(TAG, "Start LED strip");
        // LED strip general initialization, according to your led board design
        led_strip_config_t strip_config = {
            .strip_gpio_num = LED_STRIP_BLINK_GPIO,   // The GPIO that connected to the LED strip's data line
            .max_leds = LED_STRIP_LED_NUMBERS,        // The number of LEDs in the strip,
            // .led_pixel_format = LED_PIXEL_FORMAT_GRB, // Pixel format of your LED strip
            // .led_model = LED_MODEL_WS2812,            // LED strip model
            // .flags.invert_out = false,                // whether to invert the output signal
        };

        // LED strip backend configuration: RMT
        led_strip_rmt_config_t rmt_config = {
    #if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
            .rmt_channel = 0,
    #else
            // .clk_src = RMT_CLK_SRC_DEFAULT,        // different clock source can lead to different power consumption
            .resolution_hz = LED_STRIP_RMT_RES_HZ, // RMT counter clock frequency
            .flags.with_dma = false,               // DMA feature is available on ESP target like ESP32-S3
    #endif
        };

        ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip));
        ESP_LOGI(TAG, "Created LED strip object with RMT backend");
        /* Set all LED off to clear all pixels */
        led_strip_clear(led_strip);
        led_color_ex = led_color;

        ESP_LOGI(TAG, "LED parameters: nlight_colortemp(%d), nlight_brightness(%d)", nlight_colortemp, nlight_brightness);
        
        xTaskCreate(topLED_manage_task, "topLED_manage_task", 2024*2, NULL, 17, NULL);
    }
}
